package com.dd.cloud.user.service.news.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.constants.ConsultConstants;
import com.dd.cloud.common.constants.SmsConstants;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.common.utils.BigDecimalUtils;
import com.dd.cloud.common.utils.DateUtils;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.common.vo.PageReq;
import com.dd.cloud.user.entity.consult.ConsultSubscribe;
import com.dd.cloud.user.entity.doctor.DoctorDetail;
import com.dd.cloud.user.entity.news.NewsInfo;
import com.dd.cloud.user.entity.news.NewsSee;
import com.dd.cloud.user.entity.order.OrderPay;
import com.dd.cloud.user.entity.pres.PresPrescription;
import com.dd.cloud.user.mapper.news.NewsInfoMapper;
import com.dd.cloud.user.mq.MQConfig;
import com.dd.cloud.user.res.news.NewsInfoPageRes;
import com.dd.cloud.user.service.consule.IConsultSubscribeService;
import com.dd.cloud.user.service.doctor.IDoctorDetailService;
import com.dd.cloud.user.service.doctor.IDoctorUserService;
import com.dd.cloud.user.service.news.INewsInfoService;
import com.dd.cloud.user.service.news.INewsSeeService;
import com.dd.cloud.user.service.order.IOrderPayService;
import com.dd.cloud.user.service.pres.IPresPrescriptionService;
import com.zk.pay.constants.CS;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Lx
 * @version 1.0
 */
@Slf4j
@Service
public class NewsInfoServiceImpl extends ServiceImpl<NewsInfoMapper, NewsInfo> implements INewsInfoService {
    @Autowired
    private IPresPrescriptionService presPrescriptionService;
    @Autowired
    private IDoctorUserService doctorUserService;
    @Autowired
    private INewsSeeService newsSeeService;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private IOrderPayService orderPayService;
    @Autowired
    private IDoctorDetailService doctorDetailService;
    @Autowired
    private IConsultSubscribeService consultSubscribeService;

    /**
     * 查询消息列表 分页
     *
     * @param req
     * @param status
     * @return
     */
    @Override
    public IPage<NewsInfoPageRes> queryNewsInfoPage(PageReq req, Integer status) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        IPage<NewsInfoPageRes> iPage = req.pagePojo();
        iPage = getBaseMapper().queryNewsInfoPage(iPage, loginInfo.getId(), loginInfo.getType(), status);
        return iPage;
    }

    /**
     * 发送订单支付通知
     *
     * @param op
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendOrderPayNotice(OrderPay op) {
        QueryWrapper<PresPrescription> qw = new QueryWrapper<>();
        qw.lambda().eq(PresPrescription::getTencode, op.getServerNo());
        qw.lambda().select(PresPrescription::getDoctorId, PresPrescription::getName);
        PresPrescription pres = presPrescriptionService.getOne(qw);
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        ni.setContent("患者" + pres.getName() + "已支付订单" + op.getOrderNo());
        ni.setParam(op.getServerNo());
        ni.setType(2);
        ni.setMold(1);
        ni.setStatus(1);
        ni.setCreateDate(LocalDateTime.now());
        save(ni);
        NewsSee ns = new NewsSee();
        ns.setNewId(ni.getId());
        ns.setUserId(pres.getDoctorId());
        ns.setUserType(LoginInfo.UserType.DOCTOR);
        ns.setStatus(1);
        ns.setCreateDate(LocalDateTime.now());
        newsSeeService.save(ns);
    }


    /**
     * 发送医生提现打款成功通知
     *
     * @param doctorId
     * @param amount
     * @param reason
     * @param type     类型 1成功 2失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendDoctorWithdrawPaymentNotice(Integer doctorId, Integer amount, String reason, Integer type) {
        String doctorName = doctorUserService.getDoctorUserName(doctorId);
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        if (type == 1) {
            ni.setContent("【打款成功】：尊敬的" + doctorName + "，您申请的提现业务已受理成功，<span>到账金额：【" + BigDecimalUtils.divide(amount, 100).doubleValue() + "元】，</span>预计2两小时内到账，请注意查收");
        } else {
            ni.setContent("【打款失败】：尊敬的" + doctorName + "，您申请的提现业务受理失败，<span>失败原因：【" + reason + "】，</span>请知悉");
        }
        initDoctorMold2Type2AndSend(doctorId, ni, 2);
        if (type == 1) {
            Map<String, String> msg = new HashMap<>(4);
            msg.put("phone", doctorUserService.getDoctorUserPhone(doctorId));
            msg.put("name", doctorName);
            msg.put("fee", BigDecimalUtils.divide(amount, 100).toString());
            msg.put("param_type", SmsConstants.ParamType.JSON);
            msg.put("sms_template", SmsConstants.Template.PAYMENT);
            amqpTemplate.convertAndSend(MQConfig.SMS_EXCHANGE, MQConfig.SMS_KEY, msg);
        }
    }

    @Override
    public void sendApplyDoctorBindReviewNotice(Integer doctorId, Integer type) {
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        ni.setParam(String.valueOf(doctorId));
        String message = "通过";
        if (type == 1) {
            ni.setContent("尊敬的用户，您好，您申请的处方审核签约医生已经审核通过，请知悉");
        } else {
            message = "拒绝";
            ni.setContent("尊敬的用户，您好，您申请的处方审核签约医生已审核拒绝，请知悉");
        }
        initDoctorMold2Type2AndSend(doctorId, ni, 2);
        Map<String, String> msg = new HashMap<>(4);
        msg.put("phone", doctorUserService.getDoctorUserPhone(doctorId));
        msg.put("msg", message);
        msg.put("param_type", SmsConstants.ParamType.JSON);
        msg.put("sms_template", SmsConstants.Template.DOCTOR_BIND_RESULT);
        amqpTemplate.convertAndSend(MQConfig.SMS_EXCHANGE, MQConfig.SMS_KEY, msg);
    }

    @Override
    public void sendApplyDoctorBindHandleNotice(Integer doctorId) {
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        ni.setParam(String.valueOf(doctorId));
        ni.setContent("尊敬的用户，您好，您有一个处方审核签约待审核，请您及时处理");
        initDoctorMold2Type2AndSend(doctorId, ni, 2);
        Map<String, String> msg = new HashMap<>(4);
        msg.put("phone", doctorUserService.getDoctorUserPhone(doctorId));
        msg.put("param_type", SmsConstants.ParamType.JSON);
        msg.put("sms_template", SmsConstants.Template.UN_REVIEW_DOCTOR_BIND);
        amqpTemplate.convertAndSend(MQConfig.SMS_EXCHANGE, MQConfig.SMS_KEY, msg);
    }

    /**
     * 发送申请医生提交的处方审核结果通知
     *
     * @param doctorId
     * @param tencode
     * @param type     类型 1审核成功 2审核失败
     */
    @Override
    public void sendApplyDoctorPresReviewNotice(Integer doctorId, String tencode, Integer type) {
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        ni.setParam(tencode);
        String message = "通过";
        if (type == 1) {
            ni.setContent("尊敬的用户，您好，您发起的处方审核申请已审核通过，请知悉");
        } else {
            message = "拒绝";
            ni.setContent("尊敬的用户，您好，您发起的处方审核申请已审核拒绝，请知悉");
        }
        initDoctorMold2Type2AndSend(doctorId, ni, 2);
        Map<String, String> msg = new HashMap<>(4);
        msg.put("phone", doctorUserService.getDoctorUserPhone(doctorId));
        msg.put("msg", message);
        msg.put("param_type", SmsConstants.ParamType.JSON);
        msg.put("sms_template", SmsConstants.Template.REVIEW_PRES_RESULT);
        amqpTemplate.convertAndSend(MQConfig.SMS_EXCHANGE, MQConfig.SMS_KEY, msg);
    }

    /**
     * 发送审核医生处方审核待处理通知
     *
     * @param doctorId
     * @param tencode
     */
    @Override
    public void sendReviewDoctorPresHandleNotice(Integer doctorId, String tencode) {
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        ni.setParam(tencode);
        ni.setContent("尊敬的用户，您好，您有一个处方待审核，请您及时处理");
        initDoctorMold2Type2AndSend(doctorId, ni, 2);
        Map<String, String> msg = new HashMap<>(4);
        msg.put("phone", doctorUserService.getDoctorUserPhone(doctorId));
        msg.put("param_type", SmsConstants.ParamType.JSON);
        msg.put("sms_template", SmsConstants.Template.UN_REVIEW_PRES);
        amqpTemplate.convertAndSend(MQConfig.SMS_EXCHANGE, MQConfig.SMS_KEY, msg);
    }

    /**
     * 发送资料待完善消息给医生
     *
     * @param doctorId
     */
    @Override
    public void sendDoctorAuthLapseNewsNoticeAuthType1(Integer doctorId) {
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        ni.setParam(String.valueOf(doctorId));
        ni.setContent("尊敬的用户，您好，您认证的资料暂不完善，为了避免您的正常使用，请及时在【个人中心】>【认证】界面进行补充完整【点击补充认证】");
        initDoctorMold2Type2AndSend(doctorId, ni, 3);
    }

    /**
     * 发送乡村医生资质过期消息给医生
     *
     * @param doctorId
     * @param date
     */
    @Override
    public void sendDoctorAuthLapseNewsNoticeAuthType2(Integer doctorId, LocalDate date) {
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        ni.setParam(String.valueOf(doctorId));
        Period period = Period.between(LocalDate.now(), date);
        int day = period.getDays();
        ni.setContent("尊敬的用户，您好，您在平台认证的【乡村医生执业证】在" + day + "天后即将过期，为了避免您的正常使用，请尽快进行重新认证  【点击重新认证】");
        initDoctorMold2Type2AndSend(doctorId, ni, 3);
        Map<String, String> msg = new HashMap<>(4);
        msg.put("phone", doctorUserService.getDoctorUserPhone(doctorId));
        msg.put("day", String.valueOf(day));
        msg.put("param_type", SmsConstants.ParamType.JSON);
        msg.put("sms_template", SmsConstants.Template.AUTH_TYPE2_LAPSE);
        amqpTemplate.convertAndSend(MQConfig.SMS_EXCHANGE, MQConfig.SMS_KEY, msg);
    }

    /**
     * 发送互联网执业医生备案审核消息
     *
     * @param doctorId
     * @param applyId
     * @param type
     */
    @Override
    public void sendDoctorHlwFilingNoticeReviewNotice(Integer doctorId, Integer applyId, Integer type) {
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        ni.setParam(applyId.toString());
        if (type == 1) {
            ni.setContent("恭喜您，您提交的互联网医院执业申请已通过审核。");
        } else {
            ni.setContent("非常抱歉，您提交的互联网医院执业申请未通过审核。您可点击下方按钮进行重新提交申请。");
        }
        initDoctorMold2Type2AndSend(doctorId, ni, 4);
    }


    /**
     * 发送问诊预约成功消息
     */
    @Override
    public void sendConsultSuccessMessage(String orderNo) {
        OrderPay orderPay = orderPayService.getOrderPay(orderNo);
        if (orderPay == null) {
            return;
        }
        if (!CS.NOTICE_CHANNEL.SINGLE.equals(orderPay.getProduct())) {
            return;
        }
        ConsultSubscribe consultSubscribe = consultSubscribeService.getById(orderPay.getServerNo());
        if (consultSubscribe == null) {
            return;
        }
        String doctorName = getDoctorName(consultSubscribe.getDoctorId());
        String day = DateUtils.dateToString(consultSubscribe.getDay());
        String content = "恭喜您，" + consultSubscribe.getPatientName() + "已经成功预约" + doctorName + "医生的线上问诊，问诊时间:" + day + "为了避免错过医生回复，请注意查看消息。若错过就诊时间预约不可取消，医生接诊也后不可取消。";
        saveMessage("预约成功通知", 5, orderPay.getServerNo(), consultSubscribe.getPatientId(), content);
    }

    @Override
    public void sendTreatMessage(Integer id) {
        ConsultSubscribe consultSubscribe = consultSubscribeService.getById(id);
        if (consultSubscribe == null) {
            return;
        }
        String doctorName = getDoctorName(consultSubscribe.getDoctorId());
        String content = "温馨提醒，您预约了明天" + doctorName + "医生的线上问诊," + "请注意查看消息。若错过就诊时间预约不可取消，医生接诊也后不可取消。";
        saveMessage("就诊提醒", 5, String.valueOf(id), consultSubscribe.getPatientId(), content);
    }

    @Override
    public void sendOrderNotPayMessage(String orderNo, String time) {
        OrderPay orderPay = getOrderPayByOrderNo(orderNo);
        if (orderPay == null) {
            return;
        }
        String single = orderPay.getProduct();
        if (!CS.NOTICE_CHANNEL.SINGLE.equals(single)) {
            return;
        }
        ConsultSubscribe consultSubscribe = consultSubscribeService.getById(orderNo);
        if (consultSubscribe == null) {
            return;
        }
        if (consultSubscribe.getStatus() == ConsultConstants.Status.NOPAY) {
            String day = DateUtils.dateToString(consultSubscribe.getDay());
            String content = "温馨提醒，您预约" + day + "的线上问诊订单未支付，为了避免错过问诊日期，请在" + time + "内进行支付。";
            saveMessage("待缴费提醒", 6, orderPay.getServerNo(), consultSubscribe.getPatientId(), content);
        }
    }

    @Override
    public void sendPresOrderNotPayMessage(String orderNo, String time) {
        OrderPay orderPay = getOrderPayByOrderNo(orderNo);
        if (orderPay == null) {
            return;
        }
        String pre = orderPay.getProduct();
        if (!CS.NOTICE_CHANNEL.PRE.equals(pre)) {
            return;
        }
        PresPrescription presPrescription = getPresByTencode(orderPay.getTencode());
        if (presPrescription == null) {
            return;
        }
        ConsultSubscribe consultSubscribe = consultSubscribeService.getById(presPrescription.getConsultId());
        if (consultSubscribe == null) {
            return;
        }
        if (consultSubscribe.getStatus() == ConsultConstants.Status.NOPAY) {
            String content = "温馨提醒，您有一笔处方订单未支付，订单号：" + orderNo + "，为了避免处方订单被取消，请在" + time + "内内进行支付。";
            saveMessage("待缴费提醒", 7, orderPay.getServerNo(), consultSubscribe.getPatientId(), content);
        }
    }

    @Override
    public void sendEvaluateMessage(String consultId) {
        ConsultSubscribe consultSubscribe = consultSubscribeService.getById(consultId);
        if (consultSubscribe == null) {
            return;
        }
        if (consultSubscribe.getStatus() != ConsultConstants.Status.SUCC) {
            return;
        }
        String content = "尊敬的用户：您好！本次线上问诊已完成，为使我们的服务更优质。请您对我们的服务给出评价。若有其他意见的可直接客服电话0755-86159215。";
        saveMessage("待评价提醒", 8, consultId, consultSubscribe.getPatientId(), content);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendPreSuccessBuyMessage(String orderNo) {
        OrderPay orderPay = getOrderPayByOrderNo(orderNo);
        if (orderPay == null) {
            return;
        }
        String pre = orderPay.getProduct();
        if (!CS.NOTICE_CHANNEL.PRE.equals(pre)) {
            return;
        }
        PresPrescription presPrescription = getPresByTencode(orderPay.getServerNo());
        if (presPrescription == null) {
            return;
        }
        if (presPrescription.getConsultId() == null || presPrescription.getConsultId() == 0) {
            return;
        }
        ConsultSubscribe consultSubscribe = consultSubscribeService.getById(presPrescription.getConsultId());
        if (consultSubscribe == null) {
            return;
        }
        String doctorName = getDoctorName(consultSubscribe.getDoctorId());
        String content = doctorName + "医生为你开具的处方订单已支付成功，订单号：" + orderNo + "，我们将及时的处理该订单。";
        saveMessage("支付成功提醒", 9, orderPay.getServerNo(), consultSubscribe.getPatientId(), content);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendPresRefundMessage(String orderNo) {
        log.info("订单号为:{}", orderNo);
        OrderPay orderPay = getOrderPayByOrderNo(orderNo);
        if (orderPay == null) {
            return;
        }
        PresPrescription presPrescription = getPresByTencode(orderPay.getTencode());
        if (presPrescription == null) {
            return;
        }
        ConsultSubscribe consultSubscribe = consultSubscribeService.getById(presPrescription.getConsultId());
        if (consultSubscribe == null) {
            return;
        }
        String content = "温馨提醒，您有一笔处方订单已退款成功，订单号：" + orderNo + "，退款金额为" + BigDecimalUtils.divide(orderPay.getTotalFee(), 100) + "元，退款金额已原路退回，请注意查收。";
        saveMessage("退款成功提醒", 9, orderPay.getServerNo(), consultSubscribe.getPatientId(), content);
    }

    @Override
    public void sendConsultRefundOrder(String orderNo) {
        log.info("订单号为:{}", orderNo);
        OrderPay orderPay = getOrderPayByOrderNo(orderNo);
        if (orderPay == null) {
            return;
        }
        String product = orderPay.getProduct();
        if (!CS.NOTICE_CHANNEL.SINGLE.equals(product)) {
            return;
        }
        ConsultSubscribe consultSubscribe = consultSubscribeService.getById(orderPay.getServerNo());
        if (consultSubscribe == null) {
            return;
        }
        String content = "温馨提醒，您有一笔处方订单已退款成功，订单号：" + orderNo + "，退款金额为" + BigDecimalUtils.divide(orderPay.getTotalFee(), 100) + "元，退款金额已原路退回，请注意查收。";
        saveMessage("退款成功提醒", 5, String.valueOf(consultSubscribe.getId()), consultSubscribe.getPatientId(), content);
    }

    /**
     * 发送系统消息给医生处方订单发货
     *
     * @param tencode
     * @param docId
     * @param pName
     * @param expressNo
     */
    @Override
    public void sendDeliveryPres(String tencode, Integer docId, String pName, String expressNo) {
        NewsInfo ni = new NewsInfo();
        ni.setTitle("系统通知");
        ni.setParam(tencode);
        ni.setContent("患者张三药品已发货,物流单号:" + expressNo);
        initDoctorMold2Type2AndSend(docId, ni, 1);
    }

    public void saveMessage(String title, Integer mold, String param, Integer userId, String content) {
        NewsInfo ni = new NewsInfo();
        ni.setTitle(title);
        ni.setParam(param);
        ni.setContent(content);
        ni.setType(2);
        ni.setMold(mold);
        ni.setStatus(1);
        ni.setCreateDate(LocalDateTime.now());
        save(ni);
        NewsSee ns = new NewsSee();
        ns.setNewId(ni.getId());
        ns.setUserId(userId);
        ns.setUserType(LoginInfo.UserType.PATIENT);
        ns.setStatus(1);
        ns.setCreateDate(LocalDateTime.now());
        newsSeeService.save(ns);
    }


    /**
     * 初始化医生系统消息模板消息并发送
     *
     * @param doctorId
     * @param ni
     */
    private void initDoctorMold2Type2AndSend(Integer doctorId, NewsInfo ni, Integer mold) {
        ni.setType(2);
        ni.setMold(mold);
        ni.setStatus(1);
        ni.setCreateDate(LocalDateTime.now());
        save(ni);
        NewsSee ns = new NewsSee();
        ns.setNewId(ni.getId());
        ns.setUserId(doctorId);
        ns.setUserType(LoginInfo.UserType.DOCTOR);
        ns.setStatus(1);
        ns.setCreateDate(LocalDateTime.now());
        newsSeeService.save(ns);
    }


    private String getDoctorName(Integer doctorId) {
        LambdaQueryWrapper<DoctorDetail> doctorWrapper = new LambdaQueryWrapper<>();
        doctorWrapper.eq(DoctorDetail::getDoctorId, doctorId);
        DoctorDetail doctorDetail = doctorDetailService.getOne(doctorWrapper);
        String doctorName = "";
        if (doctorDetail != null) {
            doctorName = doctorDetail.getName();
        }
        return doctorName;
    }

    private PresPrescription getPresByTencode(String tencode) {
        LambdaQueryWrapper<PresPrescription> presQueryWrapper = new LambdaQueryWrapper<>();
        presQueryWrapper.eq(PresPrescription::getTencode, tencode);
        PresPrescription presPrescription = presPrescriptionService.getOne(presQueryWrapper);
        return presPrescription;
    }

    private OrderPay getOrderPayByOrderNo(String orderNo) {
        LambdaQueryWrapper<OrderPay> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderPay::getOrderNo, orderNo);
        OrderPay orderPay = orderPayService.getOne(wrapper);
        return orderPay;
    }
}
